#include <stdio.h>
#include <memory.h>

#include "tools.h"
#include "sms4.h"


static void PrintHex(const char* head, const uint8_t* m, uint32_t len) {
    printf("%s:", head);
    for (uint32_t i=0; i<len; ++i) {
        printf("%02x ", m[i]);
    }
    printf("\n");
}


static bool Test_01() {
    const uint8_t plain0[SMS4_BLOCK_SIZE] = {
		0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10
	};

    const uint8_t cipher0[SMS4_BLOCK_SIZE] = {
		0x68, 0x1e, 0xdf, 0x34, 0xd2, 0x06, 0x96, 0x5e, 0x86, 0xb3, 0xe9, 0x4f, 0x53, 0x6e, 0x42, 0x46
	};	

    const uint8_t password[SMS4_BLOCK_SIZE] = {
		0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10
	};

	uint8_t plain1[SMS4_BLOCK_SIZE];
	uint8_t cipher1[SMS4_BLOCK_SIZE];


	SMS4_WorkArea sms4;

	SMS4_Initialize(&sms4, password);

	SMS4_Encrypt(&sms4, plain0, cipher1);

	SMS4_Decrypt(&sms4, cipher0, plain1);
	
	SMS4_Finalize(&sms4);

	PrintHex("cipher: ", cipher1, sizeof(cipher1));
	PrintHex("plain: ", plain1, sizeof(plain1));
	return memcmp(cipher0, cipher1, SMS4_BLOCK_SIZE) == 0 && 
		memcmp(plain0, plain1, SMS4_BLOCK_SIZE) == 0;

}


static int Test_02() {
    const uint8_t plain0[SMS4_BLOCK_SIZE] = {
		0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10
	};

    const uint8_t cipher0[SMS4_BLOCK_SIZE] = {
		0x59, 0x52, 0x98, 0xc7, 0xc6, 0xfd, 0x27, 0x1f, 0x04, 0x02, 0xf8, 0x04, 0xc3, 0x3d, 0x3f, 0x66
	};	

    const uint8_t password[SMS4_BLOCK_SIZE] = {
		0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10
	};

	uint8_t plain1[SMS4_BLOCK_SIZE];
	uint8_t cipher1[SMS4_BLOCK_SIZE];


	SMS4_WorkArea sms4;

	SMS4_Initialize(&sms4, password);

	memcpy(cipher1, plain0, SMS4_BLOCK_SIZE);
	for (int i=0; i<1000000; i++) {
		SMS4_Encrypt(&sms4, cipher1, cipher1);
	}

	memcpy(plain1, cipher1, SMS4_BLOCK_SIZE);
	for (int i=0; i<1000000; i++) {
		SMS4_Decrypt(&sms4, plain1, plain1);
	}

	SMS4_Finalize(&sms4);

	PrintHex("cipher: ", cipher1, sizeof(cipher1));
	PrintHex("plain: ", plain1, sizeof(plain1));
	return memcmp(cipher0, cipher1, SMS4_BLOCK_SIZE) == 0 && 
		memcmp(plain0, plain1, SMS4_BLOCK_SIZE) == 0;

}

bool SM_Test_SMS4() {
	bool r  = true;

	r &= SM_TEST(Test_01());
	r &= SM_TEST(Test_02());

	return r;
}

